package org.wejob.core.log;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;

public class IndexOffset {
    MappedByteBuffer mmap;
    Topic topic;
    FileChannel fileChannel;
    RandomAccessFile indexFile;
    int warmEntries;
    public final int entrySize=16;//8字节物理位置和8字节offset
    public IndexOffset(Topic topic) throws IOException {
        this.topic=topic;
        this.indexFile= new RandomAccessFile(this.topic.name+"OffsetIndex","rw");
        this.indexFile.setLength(1024*1024*1024);
        this.fileChannel=indexFile.getChannel();
        this.mmap=fileChannel.map(FileChannel.MapMode.READ_WRITE,0,this.indexFile.length());
        this.warmEntries=8192/entrySize;
    }

    public void append(long offset,long position){
        System.out.println("append index=="+offset+" "+position);
        this.mmap.putLong(offset);
        this.mmap.putLong(position);
    }

    public IndexEntry lookup(long target){
        //返回大于等于该offset的最小Index
        System.out.println("entries  "+entries());
        if(entries()==0)
            return new IndexEntry(0,0);
        int firstHotEntry=Math.max(0,this.entries()-1-this.warmEntries);
        System.out.println("热区:  "+firstHotEntry);
        //target在热区
        if(compareIndexEntry(parseEntry(firstHotEntry), target) <0) {
            return binarySearch(firstHotEntry, this.entries() - 1,target);
        }

        //target 是否比最小的offset索引小
        if(compareIndexEntry(parseEntry( 0), target) > 0){
            System.out.println(parseEntry(0).toString());
            System.out.println("target 比最小的offset索引小");
            return new IndexEntry(-1, 0);
        }


        return binarySearch(0, firstHotEntry,target);
    }
    private int compareIndexEntry(IndexEntry indexEntry, Long target){

       return java.lang.Long.compare(indexEntry.offset,target);
    }
    IndexEntry binarySearch(int begin,int end,long target){
        // binary search for the entry
        int lo=begin;
        int hi=end;
        IndexEntry res;
        while (lo < hi) {
            //-1是为了向下取---lo=1,hi=2时,mid=1;
            int mid=(lo+hi-1)>>>1;
            res = parseEntry( mid);
            int compareResult = compareIndexEntry(res, target);
            if(compareResult < 0)//target>mid.offset
                lo = mid + 1;
            else if(compareResult > 0)//target<mid.offset
                hi = mid;
            else
                return res;//相等时直接返回
        }
        return parseEntry(lo);
    }
    public int entries(){
        return this.mmap.position()/this.entrySize;
    }

    private IndexEntry parseEntry(int slot){
        long offset=this.mmap.getLong(slot*entrySize);
        long filePosition=this.mmap.getLong(slot*entrySize+8);
        IndexEntry res=new IndexEntry(offset,filePosition);
        return res;
    }

    public static void main(String args[]) throws IOException {
        Topic topic1=new Topic("asynctopic3");
        IndexOffset indexOffset=new IndexOffset(topic1);
        IndexEntry res=indexOffset.lookup(0);
        System.out.println(res.toString());
    }
}
